/*
 moxl - Modular XML Library
 Copyright (c) 2007, Malcolm Sparks

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package moxl.relaxng.simplification.normalization.patterns;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import moxl.dom.MoxlElement;
import moxl.dom.MoxlNode;
import moxl.dom.ethereal.EtherealElement;
import moxl.dom.mutable.MutableElement;
import moxl.relaxng.schema.RelaxNgSchemaElementType;

public class ElementNormalizer
{
	private final Set<RelaxNgSchemaElementType> matchingTypes = new HashSet<RelaxNgSchemaElementType>();

	public ElementNormalizer()
	{
		matchingTypes.add(RelaxNgSchemaElementType.element);
		matchingTypes.add(RelaxNgSchemaElementType.oneOrMore);
		matchingTypes.add(RelaxNgSchemaElementType.zeroOrMore);
		matchingTypes.add(RelaxNgSchemaElementType.group);
		matchingTypes.add(RelaxNgSchemaElementType.define);
		matchingTypes.add(RelaxNgSchemaElementType.optional);
		matchingTypes.add(RelaxNgSchemaElementType.list);
		matchingTypes.add(RelaxNgSchemaElementType.mixed);
	}

	public void normalize(MoxlElement element)
	{
		int count = 0;
		for (MoxlNode node : element.getChildren())
		{
			if (matches((MoxlElement) node))
			{
				count++;
			}
		}
		if (count > 1)
		{
			transform((MutableElement) element);
		}
	}

	protected boolean matches(MoxlElement candidate)
	{
		for (RelaxNgSchemaElementType match : matchingTypes)
		{
			if (candidate.getName().equals(match.getName()))
			{
				return true;
			}
		}
		return false;
	}

	protected void transform(MutableElement element)
	{
		MutableElement group = new EtherealElement(RelaxNgSchemaElementType.group.getName());
		List<MoxlNode> childNodes = element.getChildren();
		for (Iterator<MoxlNode> it = childNodes.iterator(); it.hasNext();)
		{
			MoxlElement child = (MoxlElement) it.next();
			if (matches(child))
			{
				it.remove();
				group.addChild(child);
			}
		}
		element.addChild(group);
	}
}
